package ap

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"gitee.com/cic-cybertwin/ap/db/session"
	db "gitee.com/cic-cybertwin/ap/db/sqlc"
	"gitee.com/cic-cybertwin/ap/pb/model"
	"gitee.com/cic-cybertwin/utils/cryptotools"
	"gitee.com/cic-cybertwin/utils/generator"
	"gitee.com/cic-cybertwin/utils/protocol"
	"gitee.com/cic-cybertwin/utils/stringutils"
	"gitee.com/cic-cybertwin/utils/tlstools"
	"gitee.com/cic-cybertwin/utils/token"
	"github.com/panjf2000/gnet/v2"
	log "github.com/sirupsen/logrus"
	"google.golang.org/protobuf/proto"
	"math"
	"os"
	"strconv"
	"strings"
	"time"
)

func (ap *AP) accessHelloHandler(conn gnet.Conn, data []byte) ([]byte, error) {
	codec := protocol.CodecUtils.AccessProtocolCodec
	log.Infof("[OnTraffic]-[ACCESS HELLO]-数据包data=%s", string(data))
	// access hello类型，需要向客户端返回证书和公钥
	// 1. 加载来自ca/ap/publicKey.pem中的内容
	publicKeyFileName := "./ca/ap/publicKey.pem"
	certFileName := "./ca/ap/cert.crt"
	pkData, err := os.ReadFile(publicKeyFileName)
	if err != nil {
		log.Errorf("[OnTraffic]-[ACCESS HELLO]-读取%s文件失败", publicKeyFileName)
		return nil, err
	}
	certData, err := os.ReadFile(certFileName)
	accessHelloResp := &model.AccessHelloResp{
		PublicKey:   pkData,
		Certificate: certData,
	}
	respData, err := proto.Marshal(accessHelloResp)
	if err != nil {
		log.Errorf("[OnTraffic]-[ACCESS HELLO]-序列化accessHelloResp异常:" + err.Error())
		return nil, err
	}
	encode, _ := codec.Encode(respData, protocol.TYPE_ACCESSHELLO_RESP)
	log.Infoln("[OnTraffic]-[ACCESS HELLO]-封装TYPE_ACCESSHELLO_RESP的package")
	return encode, nil
}

func (ap *AP) hidCheckHandler(conn gnet.Conn, data []byte, packets [][]byte) error {
	request := model.HidCheckRequest{}
	err := proto.Unmarshal(data, &request)
	if err != nil {
		log.Errorf("[OnTraffic]-[ACCESS HELLO]-[hid check]-反序列化HidCheckRequest失败: %s", err.Error())
		return err
	}
	// 校验数据的合法性
	// 根据hid查找数据库中该设备对应的公钥，以供verify使用
	query := session.NewDBQuery()
	hidAndR1, err := cryptotools.RSA_Decrypt(request.EncryptedData, ap.privateKey)
	splitRes := strings.Split(string(hidAndR1), stringutils.SEP)
	if err != nil {
		log.Errorln("[OnTraffic]-[Hid check阶段]-", err.Error())
	}
	ueInfoByHid, err := query.GetUeInfoByHid(context.Background(), splitRes[0])
	if err != nil {
		log.Errorln("[OnTraffic]-[Hid Check]-无法找到对应的hid:", err.Error())
		return err
	}
	i, err := strconv.ParseInt(splitRes[1], 10, 64)
	if err != nil {
		log.Errorln("[OnTraffic]-[Hid Check]-解析r1异常:", err.Error())
		return err
	}
	cc := conn.Context().(*connContext)
	cc.a = int(i)
	p, _ := pem.Decode([]byte(ueInfoByHid.UePk))
	if p == nil {
		log.Errorln("[OnTraffic]-[Hid Check]-Invalid Hid:", splitRes[0])
		return err
	}
	pk, err := x509.ParsePKCS1PublicKey(p.Bytes)
	if err != nil {
		log.Errorln("[OnTraffic]-[Hid Check]-设备公钥无法解析：", err.Error())
		return err
	}
	verify := cryptotools.RSA_SignVerify([32]byte(request.Hash), request.Signature, pk)
	if !verify {
		log.Errorln("[OnTraffic]-[Hid Check]-设备hash&signature无法校验失败")
		return err
	}
	// 拼接ctid+r2，用pkue加密，并用ap的私钥签名+哈希
	// 校验结束后，需要把ctid发送至ue
	r2 := generator.RandomInt(1, 32)
	cc.r2 = r2
	cc.ck1 = cryptotools.Int64ToBytes(cryptotools.Power(int64(cc.a), int64(cc.r2)) % cryptotools.MODULUS)
	cc.ck1 = append(cc.ck1, cc.ck1...)
	log.Infof("[OnTraffic]-[Hid Check]-获取到ck1:%v，原料中A=%d, r2 = %d", cryptotools.Power(int64(cc.a), int64(cc.r2))%cryptotools.MODULUS, cc.a, cc.r2)
	b := cryptotools.Power(cryptotools.BASE, int64(r2)) % cryptotools.MODULUS
	transferData := []byte(fmt.Sprintf("%s||%d", ueInfoByHid.CybertwinID, b))
	//log.Infof("[OnTraffic]-[Hid Check]-包装cybertwinId和r2随机数:%s", string(transferData))
	encryptTransferData, err := cryptotools.RSA_Encrypt(transferData, pk)
	if err != nil {
		log.Errorln("[OnTraffic]-[Hid Check]-使用pkue加密返回数据时出错:", err.Error())
		return err
	}
	hash, signature := cryptotools.RSA_Sign(transferData, ap.privateKey)
	hidCheckResp := &model.HidCheckResp{
		EncryptedData: encryptTransferData,
		Hash:          hash[:],
		Signature:     signature,
	}
	hidCheckRespByte, err := proto.Marshal(hidCheckResp)
	if err != nil {
		log.Errorln("[OnTraffic]-[Hid Check]-序列化HidCheckResp异常:", err.Error())
		return err
	}
	codec := protocol.CodecUtils.AccessProtocolCodec
	encode, _ := codec.Encode(hidCheckRespByte, protocol.TYPE_HID_CHECK_RESP)
	packets = append(packets, encode)
	cc.ck2 = []byte(generator.RandomString(32))
	// 作为客户端，建立和cybertwin的连接
	if !cybertwinExists(ueInfoByHid.CybertwinID) {
		createCybertwin(ueInfoByHid.CybertwinID)
	}

	// 建立与cybertwin的连接，向cybertwin发送ck2
	err = sendCk2ToCybertwin(ueInfoByHid, cc)
	if err != nil {
		log.Errorf("[OnTraffic]-[tls transfer ck2]-发送ck2密钥失败:%s", err.Error())
		return err
	}
	return nil
}

func (ap *AP) tokenApplyHandler(conn gnet.Conn, data []byte, packets [][]byte) error {
	cc := conn.Context().(*connContext)
	decryptData, err := cryptotools.AES_Decrypt(data, cc.ck1)
	if err != nil {
		log.Errorf("[OnTraffic]-[Token Apply]-使用ck1解密失败:%s", err.Error())
		return err
	}
	tokenRequest := &model.TokenRequest{}
	err = proto.Unmarshal(decryptData, tokenRequest)
	if err != nil {
		log.Errorf("[OnTraffic]-[Token Apply]-反序列化tokenRequest失败:%s", err.Error())
		return err
	}
	log.Infoln("[OnTraffic]-[Token Apply]-成功获取tokenRequest")
	// 包装token,token使用ck2进行加密,同时还要生成r3
	pasetoMaker, err := token.NewPasetoMaker(cc.ck2)
	if err != nil {
		log.Errorf("[OnTraffic]-[Token Apply]-无法生成PasetoMaker: %s", err.Error())
		return err
	}
	r3 := generator.RandomInt(1, math.MaxInt32)
	pasetoToken, err := pasetoMaker.CreateToken(tokenRequest.Uid, tokenRequest.Ueid, time.Minute*5, int64(r3))
	if err != nil {
		log.Errorf("[OnTraffic]-[Token Apply]-生成token失败:%s", err.Error())
		return err
	}
	if err != nil {
		log.Errorf("[OnTraffic]-[Token Apply]-使用ck2加密token失败:%s", err.Error())
		return err
	}
	tokenResp := &model.TokenResp{Token: []byte(pasetoToken), R3: int32(r3)}
	tokenRespBytes, err := proto.Marshal(tokenResp)
	if err != nil {
		log.Errorf("[OnTraffic]-[Token Apply]-无法序列化TokenResp:%s", err.Error())
		return err
	}
	codec := protocol.CodecUtils.AccessProtocolCodec
	encode, err := codec.AESEncode(tokenRespBytes, protocol.TYPE_TOKEN_APPLY_RESP, cc.ck1)
	if err != nil {
		log.Errorf("[OnTraffic]-[Token Apply]-无法使用ck1对tokenResp加密: %s", err.Error())
		return err
	}
	packets = append(packets, encode)
	return nil
}

func sendCk2ToCybertwin(ueInfoByHid db.GetUeInfoByHidRow, cc *connContext) error {
	certPool := x509.NewCertPool()
	certFileLocation := "./cybertwin/ca/rootCA.pem"
	err := tlstools.AddCert(certPool, certFileLocation)
	if err != nil {
		log.Errorf("[OnTraffic]-[tls transfer ck2]-无法加载%s的证书信息:%s", certFileLocation, err.Error())
	}
	config := &tls.Config{RootCAs: certPool, InsecureSkipVerify: true}
	client := tlstools.NewTlsClient("localhost", 8887, config)
	protoCk2 := &model.PROTO_CK2{
		Ueid: ueInfoByHid.UeID,
		Ck2:  cc.ck2,
	}
	log.Infoln("[ToCybertwin]-向cybertwin发送接入信息")
	err = transferCk2(client, protoCk2)
	return err
}

func cybertwinExists(ctid string) bool {
	// todo: 判断cybertwin是否存在
	return true
}

func createCybertwin(ctid string) {
	// todo: 创建一个cybertwin示例
}

func transferCk2(client *tlstools.TLSClient, ck2 *model.PROTO_CK2) error {
	if !client.ConnectStatus() {
		err := client.Connect()
		if err != nil {
			log.Errorf("[transferCk2]-无法连接至cybertwin：%s", err.Error())
			return err
		}
	}
	marshal, err2 := proto.Marshal(ck2)
	if err2 != nil {
		log.Errorln("[transferCk2]-无法序列化Proto_ck2数据: ", err2.Error())
		return err2
	}
	_, err := client.Write(marshal)
	_ = client.Stop() // close错误忽略
	return err
}
